#include "cppdefs.h"
!svn $Id$
!=======================================================================
!  Copyright (c) 2002-2017 The ROMS/TOMS Group                         !
!    Licensed under a MIT/X style license                              !
!    See License_ROMS.txt                           Hernan G. Arango   !
!========================================== Alexander F. Shchepetkin ===
!
!BOP
!
! !MODULE: ice_coupling - message passing to and from the coupler
!
! !DESCRIPTION:
!
! Message passing to and from the coupler
!
! !REVISION HISTORY:
!
! author: Elizabeth C. Hunke, LANL
!         Tony Craig, NCAR, Dec-30-2002, modified for cpl6
!
! !INTERFACE:
!
      module ice_fakecpl
!
! !USES:
!
      use ice_kinds_mod
      use ice_blocks
      use ice_broadcast
      use ice_constants
!      USE ice_constants, only: field_type_scalar, field_loc_center, &
!               field_loc_NEcorner
      use ice_calendar
      use ice_grid
      use ice_state
      use ice_flux
      use ice_init
      use ice_history
      use ice_restart
      use ice_fileunits
      use ice_domain_size, only: max_blocks
      use ice_restart_shared, only: restart
      use ice_communicate, only: my_task, master_task
      use ice_domain, only: nblocks, distrb_info

      implicit none

      contains

      !------------------------------------

      SUBROUTINE cice_fakecpl

      USE mod_param
      USE mod_parallel
# ifdef NESTING
      USE mod_nesting
# endif
      USE mod_scalars
      USE mod_stepping
!
      USE distribute_mod
      USE mod_grid
      USE CICE_RunMod
      USE mod_forces
      USE mod_ocean
      USE mod_coupling
      USE mod_ice
      USE mod_ncparam
      use ice_gather_scatter
      use ice_calendar, only: istep, istep1, stop_now, calendar
      use ice_calendar, only: ice_time=>time, ice_dt=>dt
!
      implicit none
!
!  Local variable declarations.
!
      integer :: ng

!  KLUDGE - REVISIT THIS
      integer :: ii, jj, k
      integer ::                                                        &
     &   iblk           ,&! block indices
     &   ilo,ihi,jlo,jhi  ! beginning and end of physical domain
      type (block) ::                                                   &
     &   this_block       ! block information for current block

      real(r8) :: wrk_big(0:Lm(1)+1,0:Mm(1)+1)
      real(r8) :: wrk_small(Lm(1),Mm(1))
      real(r8) :: upsi(Lm(1),Mm(1))
      real(r8) :: vpsi(Lm(1),Mm(1))
      real(r8) :: ua(0:Lm(1)+1,0:Mm(1)+1)
      real(r8) :: va(0:Lm(1)+1,0:Mm(1)+1)
      real(r8) :: zetaa(0:Lm(1)+1,0:Mm(1)+1)
      real(r8) :: pma(0:Lm(1)+1,0:Mm(1)+1)
      real(r8) :: pna(0:Lm(1)+1,0:Mm(1)+1)
      real(r8) :: tltx(Lm(1),Mm(1))
      real(r8) :: tlty(Lm(1),Mm(1))
      real(r8) :: aicea(0:Lm(1)+1,0:Mm(1)+1)
      real(r8) :: vicea(0:Lm(1)+1,0:Mm(1)+1)
      real(r8) :: fresh_small(Lm(1),Mm(1))
      real(r8) :: sss_small(Lm(1),Mm(1))
      integer :: LBi, UBi, LBj, UBj, tile
      integer :: gfactor, gtype, status
      real(r8) :: Hscale

!
!-----------------------------------------------------------------------
! Gather fields for the ice model
!-----------------------------------------------------------------------
!
! KLUDGE here! hard-coding ng=1 (and above)
        ng = 1
        Hscale = 1.0_r8/(rho0*Cp)
        DO tile=first_tile(ng),last_tile(ng),+1
          LBi=BOUNDS(ng)%LBi(tile)
          UBi=BOUNDS(ng)%UBi(tile)
          LBj=BOUNDS(ng)%LBj(tile)
          UBj=BOUNDS(ng)%UBj(tile)
! Ocean velocity
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, u2dvar,             &
     &                OCEAN(ng)%u(LBi,LBj,N(ng),nrhs(ng)),ua)
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, v2dvar,             &
     &                OCEAN(ng)%v(LBi,LBj,N(ng),nrhs(ng)),va)
          CALL roms_u2psi(ua, upsi)
          CALL roms_v2psi(va, vpsi)
          call scatter_global(uocn, upsi, master_task, distrb_info,     &
     &             field_loc_center, field_type_scalar)
          call scatter_global(vocn, vpsi, master_task, distrb_info,     &
     &             field_loc_center, field_type_scalar)

! SST
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                OCEAN(ng)%t(LBi,LBj,N(ng),nrhs(ng),itemp),wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(sst, wrk_small, master_task, distrb_info, &
     &             field_loc_center, field_type_scalar)

! SSS
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                OCEAN(ng)%t(LBi,LBj,N(ng),nrhs(ng),isalt),wrk_big)
          sss_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(sss, sss_small, master_task, distrb_info, &
     &             field_loc_center, field_type_scalar)

! Surface tilt
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                COUPLING(ng)%Zt_avg1(LBi,LBj),zetaa)
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                GRID(ng)%pm(LBi,LBj),pma)
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                GRID(ng)%pn(LBi,LBj),pna)
          CALL roms_zeta2tlt(zetaa, pma, pna, tltx, tlty)
          call scatter_global(ss_tltx, tltx, master_task, distrb_info,  &
     &             field_loc_NEcorner, field_type_scalar)
          call scatter_global(ss_tlty, tlty, master_task, distrb_info,  &
     &             field_loc_NEcorner, field_type_scalar)

! Air temperature
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%PotT, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
! CHECK THIS
          call scatter_global(PotT, wrk_small, master_task, distrb_info,&
     &             field_loc_center, field_type_scalar)
          PotT = PotT + 273.16
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%Tair, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(Tair, wrk_small, master_task, distrb_info,&
     &             field_loc_center, field_type_scalar)
          Tair = Tair + 273.16

! Humidity
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%Hair, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(Qa, wrk_small, master_task, distrb_info,  &
     &             field_loc_center, field_type_scalar)

! Winds
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%Uwind, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(uatm, wrk_small, master_task, distrb_info,&
     &             field_loc_center, field_type_scalar)
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%Vwind, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(vatm, wrk_small, master_task, distrb_info,&
     &             field_loc_center, field_type_scalar)
          wind(:,:,:) = sqrt(uatm(:,:,:)**2                             &
     &                           + vatm(:,:,:)**2)  ! wind speed, (m/s)

! Rain
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%rain, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(frain, wrk_small, master_task,            &
     &             distrb_info, field_loc_center, field_type_scalar)
#ifdef SNOWFALL
! Snow
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%snow, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(fsnow, wrk_small, master_task,            &
     &             distrb_info, field_loc_center, field_type_scalar)
#endif

! Ice growth potential
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                ICE(ng)%wfr, wrk_big)
! units already W/m2
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(frzmlt, wrk_small, master_task,           &
     &             distrb_info, field_loc_center, field_type_scalar)

! Shortwave
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%SW_down, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(swvdr, wrk_small, master_task,            &
     &             distrb_info, field_loc_center, field_type_scalar)
! HACK has to be this order:
          fsw = swvdr
          swvdf = 0.24*swvdr
          swidr = 0.31*swvdr
          swidf = 0.16*swvdr
          swvdr = 0.29*swvdr

! Longwave
          call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,             &
     &                FORCES(ng)%LW_down, wrk_big)
          wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
          call scatter_global(flw, wrk_small, master_task, distrb_info, &
     &             field_loc_center, field_type_scalar)

! call CICE_MODEL
          zlvl = 2.0_r8   ! MERRA
          IF (iic(ng).eq.ntstart(ng) .and. .not. restart) THEN
#ifdef INI_GLORYS_ICE
! ai
            call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,           &
     &                  ICE(ng)%ai, wrk_big)
            wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
            call scatter_global(aice_init2, wrk_small, master_task,     &
     &               distrb_info, field_loc_center, field_type_scalar)
! hi
            call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,           &
     &                  ICE(ng)%hi, wrk_big)
            wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
            call scatter_global(hice_init, wrk_small, master_task,      &
     &               distrb_info, field_loc_center, field_type_scalar)
#endif
! ai
            call gather(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,           &
     &                  GRID(ng)%h, wrk_big)
            wrk_small = wrk_big(1:Lm(ng),1:Mm(Ng))
            call scatter_global(bath, wrk_small, master_task,           &
     &               distrb_info, field_loc_center, field_type_scalar)
            CALL init_state
          END IF
          CALL CICE_Run

! Fields to go back to ROMS, starting with ice concentration
          CALL gather_global(wrk_small, aice, master_task, distrb_info)
          aicea(1:Lm(ng),1:Mm(Ng)) = wrk_small
          aicea(0,1:Mm(Ng)) = aicea(1,1:Mm(Ng))
          aicea(Lm(ng)+1,1:Mm(Ng)) = aicea(Lm(ng),1:Mm(Ng))
          aicea(:,0) = aicea(:,1)
          aicea(:,Mm(Ng)+1) = aicea(:,Mm(Ng))
          call scatter(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,            &
     &             aicea, ICE(ng)%ai, ICE(ng)%ai, .true.)

! ice volume
          CALL gather_global(wrk_small, vice, master_task, distrb_info)
          vicea(1:Lm(ng),1:Mm(Ng)) = wrk_small
          vicea(0,1:Mm(Ng)) = vicea(1,1:Mm(Ng))
          vicea(Lm(ng)+1,1:Mm(Ng)) = vicea(Lm(ng),1:Mm(Ng))
          vicea(:,0) = vicea(:,1)
          vicea(:,Mm(Ng)+1) = vicea(:,Mm(Ng))
          call scatter(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar,            &
     &             vicea, ICE(ng)%hi, ICE(ng)%ai, .true.)

! Surface stress
          CALL gather_global(wrk_small, strocnxT, master_task,          &
     &                     distrb_info)
! Ocean stress from ice opposite to ice stress from ocean, divide by
! rho0.
          wrk_small = -wrk_small/rho0
          wrk_big(1:Lm(ng),1:Mm(Ng)) = wrk_small
          wrk_big(0,1:Mm(Ng)) = wrk_big(1,1:Mm(Ng))
          wrk_big(Lm(ng)+1,1:Mm(Ng)) = wrk_big(Lm(ng),1:Mm(Ng))
          wrk_big(:,0) = wrk_big(:,1)
          wrk_big(:,Mm(Ng)+1) = wrk_big(:,Mm(Ng))
          call scatter(ng, iNLM, LBi, UBi, LBj, UBj, u2dvar, wrk_big,   &
     &             FORCES(ng)%sustr, ICE(ng)%ai, .false.)
          CALL gather_global(wrk_small, strocnyT, master_task,          &
     &                     distrb_info)
          wrk_small = -wrk_small/rho0
          wrk_big(1:Lm(ng),1:Mm(Ng)) = wrk_small
          wrk_big(0,1:Mm(Ng)) = wrk_big(1,1:Mm(Ng))
          wrk_big(Lm(ng)+1,1:Mm(Ng)) = wrk_big(Lm(ng),1:Mm(Ng))
          wrk_big(:,0) = wrk_big(:,1)
          wrk_big(:,Mm(Ng)+1) = wrk_big(:,Mm(Ng))
          call scatter(ng, iNLM, LBi, UBi, LBj, UBj, v2dvar, wrk_big,   &
     &             FORCES(ng)%svstr, ICE(ng)%ai, .false.)

! Shortwave
          CALL gather_global(wrk_small, fswthru, master_task,           &
     &                       distrb_info)
          wrk_small = Hscale*wrk_small
          wrk_big(1:Lm(ng),1:Mm(Ng)) = wrk_small
          wrk_big(0,1:Mm(Ng)) = wrk_big(1,1:Mm(Ng))
          wrk_big(Lm(ng)+1,1:Mm(Ng)) = wrk_big(Lm(ng),1:Mm(Ng))
          wrk_big(:,0) = wrk_big(:,1)
          wrk_big(:,Mm(Ng)+1) = wrk_big(:,Mm(Ng))
          call scatter(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar, wrk_big,   &
     &             FORCES(ng)%srflx, ICE(ng)%ai, .false.)

! Surface tracer fluxes
          CALL gather_global(wrk_small, fhocn, master_task,             &
     &                     distrb_info)
! scale from W/m^2 to ROMS units
          wrk_small = Hscale*wrk_small
          wrk_big(1:Lm(ng),1:Mm(Ng)) = wrk_small
          wrk_big(0,1:Mm(Ng)) = wrk_big(1,1:Mm(Ng))
          wrk_big(Lm(ng)+1,1:Mm(Ng)) = wrk_big(Lm(ng),1:Mm(Ng))
          wrk_big(:,0) = wrk_big(:,1)
          wrk_big(:,Mm(Ng)+1) = wrk_big(:,Mm(Ng))
          call scatter(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar, wrk_big,   &
     &             FORCES(ng)%stflx(LBi,LBj,itemp), ICE(ng)%ai, .false.)
! add fresh water flux to salt flux
          CALL gather_global(wrk_small, fsalt, master_task,             &
     &                     distrb_info)
          CALL gather_global(fresh_small, fresh, master_task,           &
     &                     distrb_info)
!  convert units of kg/m2/s to salt (factor of 1000.)
          wrk_small = - wrk_small*1000._r8 - sss_small/rho0*fresh_small
          wrk_big(1:Lm(ng),1:Mm(Ng)) = wrk_small
          wrk_big(0,1:Mm(Ng)) = wrk_big(1,1:Mm(Ng))
          wrk_big(Lm(ng)+1,1:Mm(Ng)) = wrk_big(Lm(ng),1:Mm(Ng))
          wrk_big(:,0) = wrk_big(:,1)
          wrk_big(:,Mm(Ng)+1) = wrk_big(:,Mm(Ng))
          call scatter(ng, iNLM, LBi, UBi, LBj, UBj, r2dvar, wrk_big,   &
     &             FORCES(ng)%stflx(LBi,LBj,isalt), ICE(ng)%ai, .false.)

        END DO

      RETURN
      END SUBROUTINE cice_fakecpl
      !------------------------------------

      subroutine roms_u2psi(uvar,psivar)

      use mod_param

      real (kind=dbl_kind), intent(in) :: uvar(0:Lm(1)+1,0:Mm(1)+1)
      real (kind=dbl_kind), intent(out) :: psivar(Lm(1),Mm(1))

      integer(kind=int_kind) :: i,j   !loop index!

      !kca - changes made to uv2rho and rho2uv subroutines

      do j=1,Mm(1)
        do i=1,Lm(1)
!          if ((uvar(i+1,j).eq.c0) .or. (uvar(i,j).eq.c0)) then
!            psivar(i,j) = uvar(i+1,j) + uvar(i,j)
!          else
            psivar(i,j) = 0.5_r8 * (uvar(i+1,j) + uvar(i+1,j+1))
!          endif
!          psivar(i,j) = 0.0_r8
        enddo
      enddo

      end subroutine roms_u2psi

      !-------------------------------------

      subroutine roms_v2psi(vvar,psivar)

      use mod_param

      real (kind=dbl_kind), intent(in) :: vvar(0:Lm(1)+1,0:Mm(1)+1)
      real (kind=dbl_kind), intent(out) :: psivar(Lm(1),Mm(1))

      integer(kind=int_kind) :: i,j   !loop index

      do j=1,Mm(1)
        do i=1,Lm(1)
!          if ((vvar(i,j+1).eq.c0) .or. (vvar(i,j).eq.c0)) then
!            psivar(i,j) = vvar(i,j+1) + vvar(i,j)
!          else
            psivar(i,j) = 0.5_r8 * (vvar(i,j+1) + vvar(i+1,j+1))
!          endif
!          psivar(i,j) = 0.0_r8
        enddo
      enddo

      end subroutine roms_v2psi

      !--------------------------------------

      subroutine roms_rho2u(rhovar,uvar)

      use mod_param

      real (kind=dbl_kind), intent(in) :: rhovar(Lm(1)+2,Mm(1)+2)
      real (kind=dbl_kind), intent(out) :: uvar(Lm(1)+2,Mm(1)+2)

      integer(kind=int_kind) :: i,j   !loop index

      do j=1,Mm(1)+2
        do i=2,Lm(1)+2
          if ((rhovar(i,j).eq.c0) .or. (rhovar(i-1,j).eq.c0)) then
            uvar(i,j) = rhovar(i,j) + rhovar(i-1,j)
          else
            uvar(i,j) = 0.5_r8 * ( rhovar(i,j) + rhovar(i-1,j) )
          endif
        enddo
      enddo

      do j=1,Mm(1)+2
        !uvar(1,j) = rhovar(1,j)
         uvar(1,j) = c0
      enddo

      end subroutine roms_rho2u

      !--------------------------------------

      subroutine roms_rho2v(rhovar,vvar)

      use mod_param

      real (kind=dbl_kind), intent(in) :: rhovar(Lm(1)+2,Mm(1)+2)
      real (kind=dbl_kind), intent(out) :: vvar(Lm(1)+2,Mm(1)+2)

      integer(kind=int_kind) :: i,j   !loop index

      do i=1,Lm(1)+2
        do j=2,Mm(1)+2
          if ((rhovar(i,j).eq.c0) .or. (rhovar(i,j-1).eq.c0)) then
            vvar(i,j) = rhovar(i,j) + rhovar(i,j-1)
          else
            vvar(i,j) = 0.5_r8 * (rhovar(i,j) + rhovar(i,j-1))
          endif
        enddo
      enddo

      do i=1,Lm(1)+2
        !vvar(i,1) = rhovar(i,1)
         vvar(i,1) = c0
      enddo

      end subroutine roms_rho2v

      !--------------------------------------

      subroutine roms_zeta2tlt(zeta, pm, pn, tltx, tlty)

      use mod_param

      real (kind=dbl_kind), intent(in) :: zeta(0:Lm(1)+1,0:Mm(1)+1)
      real (kind=dbl_kind), intent(in) :: pm(0:Lm(1)+1,0:Mm(1)+1)
      real (kind=dbl_kind), intent(in) :: pn(0:Lm(1)+1,0:Mm(1)+1)
      real (kind=dbl_kind), intent(out) :: tltx(Lm(1),Mm(1))
      real (kind=dbl_kind), intent(out) :: tlty(Lm(1),Mm(1))

      integer(kind=int_kind) :: i,j   !loop index!

      real (kind=dbl_kind) :: tmp(0:Lm(1)+1,0:Mm(1)+1)

! at ROMS u-points
      do j=0,Mm(1)+1
        do i=1,Lm(1)+1
          if ((zeta(i-1,j).eq.c0) .or. (zeta(i,j).eq.c0)) then
            tmp(i,j) = c0
          else
            tmp(i,j) = 0.5*(pm(i-1,j)+pm(i,j))*(zeta(i,j)-zeta(i-1,j))
          endif
        enddo
      enddo

! at ROMS psi-points (NE_corner convention)
      do j=1,Mm(1)
        do i=1,Lm(1)
          tltx(i,j) = 0.5*(tmp(i+1,j)+tmp(i+1,j+1))
        enddo
      enddo

! at ROMS v-points
      do j=1,Mm(1)+1
        do i=0,Lm(1)+1
          if ((zeta(i,j-1).eq.c0) .or. (zeta(i,j).eq.c0)) then
            tmp(i,j) = c0
          else
            tmp(i,j) = 0.5*(pn(i,j-1)+pn(i,j))*(zeta(i,j)-zeta(i,j-1))
          endif
        enddo
      enddo

! at ROMS psi-points (NE_corner convention)
      do j=1,Mm(1)
        do i=1,Lm(1)
          tlty(i,j) = 0.5*(tmp(i,j+1)+tmp(i+1,j+1))
        enddo
      enddo

      end subroutine roms_zeta2tlt

      end module ice_fakecpl
